#pragma once

#include <winsock.h>
#include <functional>
#include <queue>
#include <thread>

class Socket {
public:
    Socket(const char *host, int port);

    Socket(SOCKET sock, sockaddr_in addr);

    ~Socket();

    Socket(const Socket &) = delete;

    Socket &operator=(const Socket &) = delete;

    [[maybe_unused]] Socket(Socket &&other) noexcept;

    Socket &operator=(Socket &&other) noexcept;

    void close();

    void send(const char *buf, int len) const;

    void recv(char *buf, int len) const;

    template<int N>
    void send(const char(&buf)[N]) const {
        send(buf, sizeof(buf));
    }

    template<int N>
    void recv(char(&buf)[N]) const {
        recv(buf, sizeof(buf));
    }

protected:
    SOCKET sock{};
    sockaddr_in addr{};
};

class Server : public Socket {
public:
    Server(const char *host, int port);

    void listen(const std::function<void(Socket)> &handle);
};

class Client : public Socket {
public:
    Client(const char *host, int port);
};